/**
 * @asignatura: Procesadores de Lenguajes.
 * @autor:      Anthony Vittorio Russo Cabrera
 * @curso:      2012/2013
 * @práctica:   02 - Pseudo-Analizador Léxico
 * @descripción:
 * Práctica 2: Comenzando con Analizador Léxico
 * En la práctica de esta semana vamos a plantear el acercamiento a un 
 * analizador léxico. Objetivo: Construir un pseudo-analizador léxico que cumpla
 * con las siguientes tareas:
 *  1.- Detectar que un código JAVA se encuentran dentro del conjunto de 
 *  caracteres especificado en un fichero, este puede venir dado por un fichero
 *  de texto o por un XML.
 *  2.- Detectar que este código JAVA, las palabras reservadas que 
 *  especificaremos en un fichero, este puede venir dado por un fichero de texto
 *  o por un XML.
 *  3.- Detectar el conjunto de bloques y especificarlos en la salida de la
 *  práctica.
 *  4.- La práctica debe contener un test unitario para cada uno de las tareas
 *  mencionadas. Y debe ser compilada y ejecutada a través de un fichero ANT.
 *  5.- La práctica debe tener sus propios test de comprobación
 */
package pl.p02;

import java.util.HashMap;

public class Blocks {
  private Integer                    totalBlocks;
  private Integer                    openBlock;
  private HashMap<Integer, Integer>  tmp;        // Level-> NºBlock
  private HashMap<Integer, String[]> report;     // NºBlock -> [Level,init,end]

  public Blocks() {
    totalBlocks = 0;
    openBlock = 0;
    tmp = new HashMap<Integer, Integer>();
    report = new HashMap<Integer, String[]>();
  }

  public void parse(String line) throws LexicalException {
    String description = null;
    String[] info = null;
    int no_line = LexicalException.file.no_line;

    for (int no_column = 0; no_column < line.length(); no_column++) {
      if (line.charAt(no_column) == '{') {
        totalBlocks++;
        openBlock++;
        info = new String[3];
        info[0] = openBlock.toString();
        info[1] = "[" + no_line + "," + (no_column + 1) + "]";
        info[2] = "Unknown";
        tmp.put(openBlock, totalBlocks);
        report.put(totalBlocks, info);
      }// if

      if (line.charAt(no_column) == '}') {
        if (openBlock > 0) {
          Integer key = tmp.get(openBlock);
          info = report.get(key);
          info[2] = "[" + no_line + "," + (no_column + 1) + "]";
          report.put(key, info);
          openBlock--;
        } else {
          description += "[" + no_line + "," + (no_column + 1) + "] = '}'\n";
        }// if-else
      }// if
    }// for

    if (description != null) {
      description = "Cierre de bloque erroneo:\n" + description;
      throw new LexicalException(description);
    }// if
  }// parse

  public void check() throws LexicalException {
    if (openBlock != 0) {
      throw new LexicalException("Bloques descompensados");
    }// if
  }// check

  public String report() {
    String result = "Bloques encontrados:\n"
        + "No.Bloque -> [Profundidad, Abierto, Cerrado]\n"
        + "--------------------------------------------\n";
    for (Integer key : report.keySet()) {
      result += key.toString() + " -> [";
      String[] info = report.get(key);
      result += "Level=" + info[0] + ", ";
      result += "'{'=" + info[1] + ", ";
      result += "'}'=" + info[2] + " ]\n";
    }// for
    result += "--------------------------------------------\n";
    return result;
  }// report
}// Block
